package testbug

import (
	block "blockChain/singleBlock"
	"fmt"
	"time"
)

var (
	FirstNode block.Block = block.Block{
		Previous:      block.EMPTY_BLOCK,
		Nonce:         0,
		BitsThreshold: "000000c",
		Birth:         "2021年",
		SelfHash:      "a9c8ebf0e73cb53c94096344dfff8804",
		Height:        1,
	}
	Node2 block.Block = block.Block{
		Previous:      "a9c8ebf0e73cb53c94096344dfff8804",
		Nonce:         13475828,
		BitsThreshold: "000000c",
		Birth:         "17:00:49",
		SelfHash:      "b0694051f1a5a9a6bb35caeaa9761853",
		Height:        block.UNKNOWN_HEIGHT,
	}
	Node3 block.Block = block.Block{
		Previous:      "b0694051f1a5a9a6bb35caeaa9761853",
		Nonce:         3299808,
		BitsThreshold: "000000c",
		Birth:         "17:00:51",
		SelfHash:      "99cd7b5542a8a47ac6a76cdcbb5fafcf",
		Height:        block.UNKNOWN_HEIGHT,
	}
	Node4 block.Block = block.Block{
		Previous:      "99cd7b5542a8a47ac6a76cdcbb5fafcf",
		Nonce:         18202987,
		BitsThreshold: "000000c",
		Birth:         "17:00:58",
		SelfHash:      "95874ec960c30d4fff85cdbc0f6a2c04",
		Height:        block.UNKNOWN_HEIGHT,
	}
	Node5 block.Block = block.Block{
		Previous:      "95874ec960c30d4fff85cdbc0f6a2c04",
		Nonce:         2982319,
		BitsThreshold: "000000c",
		Birth:         "17:00:59",
		SelfHash:      "24d821ba8de5bc25e926194ef94bf1ae",
		Height:        block.UNKNOWN_HEIGHT,
	}
)

func TestBlockBuffer() {
	const zzz = "zzz"
	a := block.Block{}
	a.Initialize(block.EMPTY_BLOCK, zzz)
	time.Sleep(time.Second)

	b := block.Block{}
	b.Initialize(a.SelfHash, zzz)
	time.Sleep(time.Second)

	c := block.Block{}
	c.Initialize(b.SelfHash, zzz)
	time.Sleep(time.Second)

	d := block.Block{}
	d.Initialize(c.SelfHash, zzz)
	time.Sleep(time.Second)

	e := block.Block{}
	e.Initialize(a.SelfHash, zzz)
	time.Sleep(time.Second)

	f := block.Block{}
	f.Initialize(e.SelfHash, zzz)
	time.Sleep(time.Second)

	g := block.Block{}
	g.Initialize(a.SelfHash, zzz)
	time.Sleep(time.Second)

	h := block.Block{}
	h.Initialize(g.SelfHash, zzz)
	time.Sleep(time.Second)

	i := block.Block{}
	i.Initialize(h.SelfHash, zzz)
	time.Sleep(time.Second)

	j := block.Block{}
	j.Initialize(i.SelfHash, zzz)
	time.Sleep(time.Second)

	k := block.Block{}
	k.Initialize(j.SelfHash, zzz)
	time.Sleep(time.Second)

	// 悬空
	x := block.Block{}
	x.Initialize("123", zzz)
	time.Sleep(time.Second)

	y := block.Block{}
	y.Initialize(x.SelfHash, zzz)
	time.Sleep(time.Second)

	z := block.Block{}
	z.Initialize(y.SelfHash, zzz)
	time.Sleep(time.Second)

	// 绕圈
	o := block.Block{}
	o.Initialize("s", zzz)
	o.SelfHash = "o"

	p := block.Block{}
	p.Initialize(o.SelfHash, zzz)
	p.SelfHash = "p"

	q := block.Block{}
	q.Initialize(p.SelfHash, zzz)
	q.SelfHash = "q"

	s := block.Block{}
	s.Initialize(q.SelfHash, zzz)
	s.SelfHash = "s"

	bufferPool := make(map[string]block.Block)
	bufferPool[a.SelfHash] = a
	bufferPool[b.SelfHash] = b
	bufferPool[c.SelfHash] = c
	bufferPool[d.SelfHash] = d
	bufferPool[e.SelfHash] = e
	bufferPool[f.SelfHash] = f
	bufferPool[x.SelfHash] = x
	bufferPool[y.SelfHash] = y
	bufferPool[z.SelfHash] = z
	bufferPool[g.SelfHash] = g
	bufferPool[h.SelfHash] = h
	bufferPool[i.SelfHash] = i
	bufferPool[j.SelfHash] = j
	bufferPool[k.SelfHash] = k
	bufferPool[o.SelfHash] = o
	bufferPool[p.SelfHash] = p
	bufferPool[q.SelfHash] = q
	bufferPool[s.SelfHash] = s

	result := block.CalculateHeight(bufferPool, p.SelfHash)
	fmt.Println("原先区块数量:", len(bufferPool))
	fmt.Println("最长的：", result)

	for _, b := range bufferPool {
		if b.Height == block.UNKNOWN_HEIGHT {
			fmt.Println(b.SelfHash, "未知")
		} else if b.Height == block.CIRCLE {
			fmt.Println(b.SelfHash, "成环")
		} else {
			fmt.Println(b.SelfHash, "正常高度", b.Height)
		}
	}
	tail := block.GetLongestChainTail(bufferPool)
	fmt.Println("---------全面计算--------")
	if tail.SelfHash == k.SelfHash {
		fmt.Println("函数正确")
	} else {
		fmt.Println("错了")
	}
	fmt.Println("剩余区块数量:", len(bufferPool))
	for _, b := range bufferPool {
		if b.Height == block.UNKNOWN_HEIGHT {
			fmt.Println(b.SelfHash, "未知")
		} else if b.Height == block.CIRCLE {
			fmt.Println(b.SelfHash, "成环")
		} else {
			fmt.Println(b.SelfHash, "正常高度", b.Height)
		}
	}
}

func TestMining() {
	a := block.Block{}
	a.Initialize(block.EMPTY_BLOCK, "000000c")
	answer := a.Nonce
	for {
		raw := fmt.Sprintf("%s%d", a.Previous, answer)
		check := block.CalculateHash([]byte(raw))
		if check <= a.BitsThreshold {
			break
		}
		answer++
	}
	a.SetSolution(answer)
	a.SetTime(time.Now().Format("15:04:05"))
	if a.IsValid() {
		fmt.Println("挖矿成功")
	} else {
		fmt.Println("挖矿失败")
	}
}

func miningTask(prev string, threshold string) block.Block {
	a := block.Block{}
	a.Initialize(prev, threshold)
	answer := a.Nonce
	for {
		raw := fmt.Sprintf("%s%d", a.Previous, answer)
		check := block.CalculateHash([]byte(raw))
		if check <= a.BitsThreshold {
			break
		}
		answer++
	}
	a.SetSolution(answer)
	a.SetTime(time.Now().Format("15:04:05"))
	return a
}

func GenerateBlockChain(length int, threshold string) {
	firstNode := block.Block{}
	firstNode.Initialize(block.EMPTY_BLOCK, threshold)
	firstNode.Height = 1
	firstNode.SetTime("2021年")
	firstNode.SetSolution(0)
	fmt.Println(firstNode)
	tmp := firstNode
	for x := 2; x <= length; x++ {
		tmp = miningTask(tmp.SelfHash, threshold)
		fmt.Println(tmp)
	}
}
